#define TESTMODE	1
#define TESTPC		0x00013e

/* Author: Chris Wilkerson;   Created: Thu Aug 12 16:19:58 PDT 2004
 * Description: Branch predictor driver.
*/

#include <cstdio>
#include <cstdlib>
#include "tread.h"

// include and define the predictor
#include "predictor.h"
PREDICTOR predictor;

#ifndef TESTMODE

// usage: predictor <trace>
int
main(int argc, char* argv[])
{
    using namespace std;


    if (2 != argc) {
        printf("usage: %s <trace>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    cbp_trace_reader_c cbptr = cbp_trace_reader_c(argv[1]);
    branch_record_c br;

    // read the trace, one branch at a time, placing the branch info in br
    while (cbptr.get_branch_record(&br)) {

        // ************************************************************
        // Competing predictors must have the following methods:
        // ************************************************************

        // get_prediction() returns the prediction your predictor would like to make
        bool predicted_taken = predictor.get_prediction(&br, cbptr.osptr);

        // predict_branch() tells the trace reader how you have predicted the branch
        bool actual_taken    = cbptr.predict_branch(predicted_taken);
            
        // finally, update_predictor() is used to update your predictor with the
        // correct branch result
        predictor.update_predictor(&br, cbptr.osptr, actual_taken);

    }
#
}

#endif
#ifdef TESTMODE

#include <iostream>
#include <fstream>

using namespace std;

ifstream fin;
ofstream fout;

int load_init_state(char*);
int display_next_state();
int read_branch_record(branch_record_c&, bool&);
int update_statistics(branch_record_c&, bool, bool);
int display_branch_record(branch_record_c&, bool, bool);
int display_statistics();

//int   mis_preds     = (stat_num_cc_branches - stat_num_correct_predicts);
//float mis_pred_rate = float(mis_preds)/(float(stat_num_insts) / 1000);

int mis_preds = 0;
int stat_num_insts = 0;
int mis_pred_rate = 0;

int stat_num_branches = 0;
int stat_num_cc_branches = 0;
int stat_num_predicts = 0;

int prev_history;

int main(int argc, char *argv[])
{
        PREDICTOR predictor;
	bool predicted_taken;
	bool actual_taken;

	//cbp_trace_reader_c cbptr = cbp_trace_reader_c(argv[1]);
       	branch_record_c br;

        if (2 != argc  && 3 != argc) {
            cout << "\nusage" << argv[0] << " <trace_in_ascii>\n"; 
        }   
        else 
        {
		if (3 == argc)
			load_init_state(argv[2]);

		fin.open(argv[1]);

    		while (read_branch_record(br, actual_taken)) {
		
		++stat_num_insts;

		prev_history = BranchHistory;

        	// get_prediction() returns the prediction your predictor would like to make
	        predicted_taken = predictor.get_prediction(&br);

	        // finally, update_predictor() is used to update your predictor with the
	        // correct branch result
	        predictor.update_predictor(&br, actual_taken);

		display_branch_record(br, actual_taken, predicted_taken );

		display_next_state();

		update_statistics(br, actual_taken, predicted_taken);
		
		}

		display_statistics();
        }

	fin.close();


}

int load_init_state(char* initfile)
{
	int index;

	ifstream fin;

	fin.open(initfile);

	fin.setf( ios_base::hex, ios_base::basefield );	fin >> index; 
	cout << "Initial State:" << endl;
	cout << "LP GP GC" << endl;	

	while(!fin.eof())
	{
		LocalHistory[TESTPC] = index;
		fin >> LocalPrediction[index];
		fin >> GlobalPrediction[index];
		fin >> GlobalChoice[index];

		cout << LocalPrediction[index] << " ";
		cout << GlobalPrediction[index] << " ";
		cout << GlobalChoice[index] << " ";
		cout << hex << "Index: " << index << endl;

		fin >> index;
	}

	BranchHistory = 0;

	fin.close();

	return 0;
}

int display_next_state()
{
	/*
	cout << "Current History: ";
	cout << hex << prev_history << " ";
	*/
	//cout << LocalPrediction[BranchHistory] << " " << GlobalPrediction[BranchHistory] << " " << GlobalChoice[BranchHistory] << " ";
	cout << LocalPrediction[prev_history] << " " << GlobalPrediction[prev_history] << " " << GlobalChoice[prev_history] << " ";
	cout << "Next History: ";
	cout << hex << BranchHistory;
	cout << endl;

	return 0;
}

int read_branch_record(branch_record_c& br, bool& actual_taken)
{
	int result;
	fin.setf( ios_base::hex, ios_base::basefield );		

	fin >> br.instruction_addr;

	if(!fin.eof())
	{
		if(br.instruction_addr == 0xFFFFFF)
		{
			BranchHistory = 0;
			LocalHistory[PC] = 0;

			cout << "***********FLUSHED***********" << endl;
			fin >> br.instruction_addr;
		}
			
		
		fin >> br.branch_target;
		fin >> br.is_indirect;
		fin >> br.is_conditional;
		fin >> br.is_call;
		fin >> br.is_return;
		fin >> actual_taken;

		result = 1;
	}
	else
		result = 0;

	return result;
}

int display_branch_record(branch_record_c& br, bool actual_taken, bool predicted_taken)
{
	//cout << endl << hex;
	//cout << "br.instruction_addr:" << br.instruction_addr << endl;

/*	cout << "br.branch_target:" << br.branch_target << endl;
	cout << "br.is_indirect;" << br.is_indirect << endl;
	cout << "br.is_conditional;" << br.is_conditional << endl;
	cout << "br.is_call;" << br.is_call << endl;
	cout << "br.is_return;" << br.is_return << endl;
*/
	//cout << "predicted_taken:" << predicted_taken << endl;
	cout << "predicted_taken:" << predicted_taken << " ";
	//cout << "actual_taken:" << actual_taken << endl;
	cout << "actual_taken:" << actual_taken << " ";

	return 0;
}

int update_statistics(branch_record_c& br, bool actual_taken, bool predicted_taken)
{
	++stat_num_branches;

	if(predicted_taken != actual_taken)
		++mis_preds;

	return 0;
}
	

	
			

int display_statistics()
{
    cout << "*********************************************************\n";
    float mis_pred_rate = float(mis_preds)/(float(stat_num_branches) / 100);
    cout << "midpredict rate (%)    :" << mis_pred_rate << endl;
    cout << "total branches         :" << stat_num_branches << endl;
    cout << "total correct predicts :" << (stat_num_branches - mis_preds) << endl;
    cout << "*********************************************************\n";

    return 0;
}

#endif

